In this document, we analyse missing data patterns in the dataset.
First of all, we noticed that there are some issues with the dataset and therefore, for now, we restrict the dataset to observations not subject to these issues. In particular, we do not have any pollution data for 2014 nor for NO in 2015 and very few observations for PMs in 2019. These issue do not come from actual missing data but are due to issue with the package we used to access the pollution data. These data are available through the EEA interface.
Share of missing data in covariates
Error: Can't combine `year` <factor<ea356>> and `city` <double>.
In order to understand these previous results, we break down the analysis by year and represent the results in a graph, for readability.

In complete case analyses, observations for which any variable is missing are dropped. One may therefore wonder what is the share of dropped observations in a complete case analysis. We only consider variables which are potentially relevant. We also drop the UV radiation variable due to its large share of missingness.
Carrying out a complete case analysis would lead to drop 54.9679616% of the observations. Only considering missing covariates (and not missingness in concentration data) would lead to drop 50.3371618% of the observations.
Location of measurement stations
The stations considered are located in the 17 biggest largest in France:
Missing data patterns in air pollution data
Here, we investigate whether missing pollutant concentration data varies across different dimentions.
The overall share of missing values is 0.046308.
Balance grahs
we first investigate whether covariates are ballanced between observations for which concentration data is missing and non missing.

It seems that most weather covariates are balanced between the two groups. Average temperature and UV radiation may however be slightly different between the two groups.
We can refine this analysis by looking separately across cities.
data_clean_continuous <- data %>%
select(elevation:elevation_weather_station, rainfall_height:school_holiday, missing, city)
# we compute the absolute difference between non-missing and missing observations
data_abs_difference <- data_clean_continuous %>%
group_by(city, missing) %>%
summarise_all(., ~ mean(., na.rm = TRUE)) %>%
pivot_longer(cols = -c(city, missing), names_to = "variable", values_to = "average") %>%
arrange(city, variable) %>%
group_by(city, variable) %>%
summarise(abs_difference = abs(average[2] - average[1]))
# we compute the standard deviation of the non-missing variables
data_sd <- data_clean_continuous %>%
filter(missing == FALSE) %>%
select(-missing) %>%
group_by(city) %>%
summarise_all(., ~ sd(., na.rm = TRUE)) %>%
pivot_longer(cols = -c(city), names_to = "variable", values_to = "sd_non_missing")
# we create the data for the love plot : we scale the absolute difference by the sd_non_missing
data_abs_difference %>%
left_join(data_sd, by = c("city", "variable")) %>%
mutate(standardized_difference = abs_difference/sd_non_missing) %>%
select(-c(abs_difference, sd_non_missing)) %>%
filter(!is.na(standardized_difference)) %>%
ggplot(aes(y = fct_rev(variable), x = standardized_difference)) +
geom_vline(xintercept = 0) +
geom_vline(xintercept = 0.1, color = "#FAB737") +
geom_point() +
facet_wrap(~ city) +
labs(title = "Covariate balance" , x = "Standardized Mean Differences", y = "")

Evolution of the share of missing values with the values of covariates
In this section, we investigate whether the share of missing values varies with the values of covariates. One may expect that, for extreme values of some covariates, such as temperature, wind speed or precipitation level for example, measurement instruments are more likely to be defective, leading to more missing values.
Across pollutants

One can notice that the share of missing values varies across pollutants, up to about a factor two. This higlights the potential necessity of analysing missingness patterns independently across pollutants.
Across locations
We look weather missingness patterns vary across location characteristics.
[[1]]
[[2]]
[[3]]
[[4]]





Across dates and time
We then investigate whether the share of missing values evolves with dates and time.
[[1]]
[[2]]
[[3]]
[[4]]
[[5]]
[[6]]
[[7]]
Overall, we notice that, along the time dimension data almost seems to be missing at random appart from a decreasing trend in the proportion of missing data
We also explore more closely these patterns for some variables by decomposing them by year, month or pollutant.

Across weather variables
[[1]]
[[2]]
[[3]]
[[4]]
[[5]]
[[6]]
[[7]]
[[8]]
[[9]]
[[10]]
[[11]]
[[12]]












Only consider first missing value
If data is missing due to external factors, what matters might be the value of these external factor when the data started missing, ie potentially when the sensor first became defective. As a consequence, we plot the same graphs as before but only considering hours were the data started missing, not considering later and consecutive missing observations.
As compared to the full sample, the share of missing data decreases since we discarded many observations with missing values (every observation which was not the first observation of their period of missing data). Hence, the share of missing data is not informative in itself, only potential differences in this share across “grouping variables”.
Error in group_by(site, pollutant) : object 'site' not found
Simultaneous missingness
In this section, we analyse whether some patterns of simultaneous missingness appear in the data. We wonder whether, for a given station, data is simultaneously missing for several pollutants or whether, for a given city, data is simultaneously missing for several stations.
Across pollutants
We investigate whether, in a given station, when one pollutant is missing, other pollutants are also missing. Such a missingness pattern could arise if sensors for different pollutants function jointly.
We count the number of pollutants which are simultaneously missing for every station*date couple. Note that this analysis does not consider that an observation is missing when a given station is closed for a pollutant.
| 0 |
3682071 |
0.8996952 |
| 1 |
300244 |
0.0733631 |
| 2 |
83885 |
0.0204969 |
| 3 |
17271 |
0.0042201 |
| 4 |
6288 |
0.0015364 |
| 5 |
2139 |
0.0005227 |
| 6 |
678 |
0.0001657 |
We could also investigate whether this pattern varies with various weather variables.
Now, part of the stations do not measure values for all pollutants. Thus, it is interesting to compute the proportion of pollutants measured by station for which data is missing.
| 0.0000000 |
3682071 |
0.8996952 |
NA |
| 0.1666667 |
26765 |
0.0065399 |
0.0652002 |
| 0.2000000 |
44184 |
0.0107961 |
0.1076333 |
| 0.2500000 |
71990 |
0.0175904 |
0.1753694 |
| 0.3333333 |
63008 |
0.0153957 |
0.1534890 |
| 0.4000000 |
8892 |
0.0021727 |
0.0216611 |
| 0.5000000 |
72044 |
0.0176036 |
0.1755009 |
| 0.6000000 |
1989 |
0.0004860 |
0.0048453 |
| 0.6666667 |
14931 |
0.0036483 |
0.0363723 |
| 0.7500000 |
1659 |
0.0004054 |
0.0040414 |
| 0.8000000 |
823 |
0.0002011 |
0.0020048 |
| 0.8333333 |
148 |
0.0000362 |
0.0003605 |
| 1.0000000 |
104072 |
0.0254295 |
0.2535219 |
Since for analyses studying the link btween air pollution and health have a particular focus on background station, we carry out the same analysis for these stations.
Across stations in a city
Ultimately, analyses studying health effects of air pollution often only use one measure of concentration per city and per date. In most cases, there are several air pollution measurement stations per city. To get a unique measure of air pollution for a given city, the common practice consists in averaging pollutants concentrations from all background stations in this city. We may wonder to what extent concentration data is simultaneously missing in several stations of a given city. We therefore compute the average proportion of stations per city in which data missing.
| 0.0000000 |
4186511 |
0.9334591 |
NA |
| 0.1666667 |
17198 |
0.0038346 |
0.0576279 |
| 0.2000000 |
3998 |
0.0008914 |
0.0133967 |
| 0.2500000 |
1929 |
0.0004301 |
0.0064638 |
| 0.3333333 |
48112 |
0.0107274 |
0.1612160 |
| 0.4000000 |
90 |
0.0000201 |
0.0003016 |
| 0.5000000 |
86908 |
0.0193777 |
0.2912154 |
| 0.6000000 |
2 |
0.0000004 |
0.0000067 |
| 0.6666667 |
10495 |
0.0023401 |
0.0351671 |
| 0.7500000 |
8 |
0.0000018 |
0.0000268 |
| 1.0000000 |
129692 |
0.0289172 |
0.4345781 |
Length of periods with missing observations
In this section, we explore the length of periods with missing observations. This length may provide information on causes of missingness. Missing observations for long periods of time may be indicative of cluttered filters of broken instrument. We also explore whether the length of missingness patterns is correlated with weather variables.
First, we explore the length of missing observations by looking at the displaying, in an heatmat, for each couple station*date, whether concentration data is missing. We break this down into years for readibility.
heatmap_missingness <- function(df, y) {
graph <- df %>%
filter(year == y) %>%
group_by(city) %>%
mutate(site_city = paste(city, as.integer(factor(site)), sep = "_")) %>%
ungroup() %>%
ggplot(aes(x = date, y = site_city, fill = missing)) +
geom_tile() +
# theme_minimal() +
facet_wrap(~ pollutant) +
scale_fill_manual(values = c("#580E3C", "#FAB737")) +
theme(panel.grid.major.y = element_blank()) +
labs(title = paste("Intervals with missing concentration data pollutant in", y, sep = " "), x = "Date", y = "Air pollution station")
return(graph)
}
purrr::map(c(2013, 2015:2019), heatmap_missingness, df = data)
[[1]]
[[2]]
[[3]]
[[4]]
[[5]]
[[6]]






Then, we look at the length of periods with missing data. First, we can either count each the number of periods with a given length (eg 3 periods have a length of missing data of 5 hours) or count the number of dates belonging to periods with a given length (considering the same example, 15 dates belong to a period of missing data of length 5 hours). We denote the former case “One observation per period” and the later “One observation per date”.
Distribution of lengths of missing data

Coorelation between missingness length and weather variables
plot_evolution_length <- function(df, var, per) {
var_name <- str_replace_all(var, pattern = "_", replacement = " ")
graph <- df %>%
ggplot() +
geom_bin2d(aes(x = .data[[var]], y = .data[["length_period_missing"]])) +
scale_y_continuous(trans = 'log10') +
labs(title = paste("Relationship between length of periods with missing data", var_name), subtitle = paste("One observation per", per), x = str_to_sentence(var_name), y = "Length of missing period (in hours)")
if (substr(var, 1, 8) == "wind_dir") {
graph <- graph +
coord_polar()
}
return(graph)
}
Here we consider the weather when variables started missing. It make sense to look into this because if missingness is caused by some weather feature, The weather during the first missing observation would be the one to look into.
LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgbWlzc2luZyBkYXRhIHBhdHRlcm5zIgphdXRob3I6CiAgLSBuYW1lOiBWaW5jZW50IEJhZ2lsZXQgCiAgICB1cmw6IGh0dHBzOi8vd3d3LnNpcGEuY29sdW1iaWEuZWR1L2V4cGVyaWVuY2Utc2lwYS9zaXBhLXByb2ZpbGVzL3ZpbmNlbnQtYmFnaWxldAogICAgYWZmaWxpYXRpb246IENvbHVtYmlhIFVuaXZlcnNpdHkKICAgIGFmZmlsaWF0aW9uX3VybDogaHR0cHM6Ly93d3cuY29sdW1iaWEuZWR1LwogIC0gbmFtZTogTMOpbyBaYWJyb2NraSAKICAgIHVybDogaHR0cHM6Ly93d3cucGFyaXNzY2hvb2xvZmVjb25vbWljcy5ldS9lbi8KICAgIGFmZmlsaWF0aW9uOiBQYXJpcyBTY2hvb2wgb2YgRWNvbm9taWNzCiAgICBhZmZpbGlhdGlvbl91cmw6IGh0dHBzOi8vd3d3LnBhcmlzc2Nob29sb2ZlY29ub21pY3MuZXUvZW4vCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IG5vCiAgICB0aGVtZTogc2ltcGxleAogICAgaGlnaGxpZ2h0OiBweWdtZW50cwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogc2ltcGxleAogICAgaGlnaGxpZ2h0OiBweWdtZW50cwotLS0KPCEtLSBvdXRwdXQ6IGRpc3RpbGw6OmRpc3RpbGxfYXJ0aWNsZSAtLT4KPCEtLSAtLS0gLS0+Cgo8c3R5bGU+CmJvZHkgewp0ZXh0LWFsaWduOiBqdXN0aWZ5fQo8L3N0eWxlPgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGtuaXRyKQpvcHRzX2NodW5rJHNldChmaWcucGF0aCA9ICJpbWFnZXMvIiwKICAgICAgICAgICAgICAgY2FjaGUucGF0aCA9ICJjYWNoZS8iLAogICAgICAgICAgICAgICBjYWNoZSA9IEZBTFNFLAogICAgICAgICAgICAgICBlY2hvID0gVFJVRSwKICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsCiAgICAgICAgICAgICAgIG91dC53aWR0aCA9ICI3MCUiLAogICAgICAgICAgICAgICBkcGkgPSAzMDAsCiAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICJjZW50ZXIiKSAgCmBgYCAgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtZWRpb2NyZXRoZW1lcykKIyBsaWJyYXJ5KG1hcHMpCmxpYnJhcnkobHVicmlkYXRlKQojIGxpYnJhcnkobGVhZmxldCkKCnNldF9tZWRpb2NyZV9hbGwoKQpgYGAKCmBgYHtyIGluY2x1ZGU9RkFMU0V9Cm1ldGFkYXRhX3BvbGx1dGlvbiA8LSByZWFkUkRTKCIuLi9PdXRwdXRzL2NsZWFuX21ldGFkYXRhX3BvbGx1dGlvbi5SRFMiKQpkYXRhX2ltcHV0YXRpb24gPC0gcmVhZFJEUygiLi4vT3V0cHV0cy9kYXRhX2ltcHV0YXRpb24uUkRTIikKIyByYXcgPC0gcmVhZFJEUygiLi4vT3V0cHV0cy9yYXdfYWlyX3BvbGx1dGlvbl9kYXRhLlJEUyIpCmBgYAoKSW4gdGhpcyBkb2N1bWVudCwgd2UgYW5hbHlzZSBtaXNzaW5nIGRhdGEgcGF0dGVybnMgaW4gdGhlIGRhdGFzZXQuIAoKRmlyc3Qgb2YgYWxsLCB3ZSBub3RpY2VkIHRoYXQgdGhlcmUgYXJlIHNvbWUgaXNzdWVzIHdpdGggdGhlIGRhdGFzZXQgYW5kIHRoZXJlZm9yZSwgZm9yIG5vdywgd2UgcmVzdHJpY3QgdGhlIGRhdGFzZXQgdG8gb2JzZXJ2YXRpb25zIG5vdCBzdWJqZWN0IHRvIHRoZXNlIGlzc3Vlcy4gSW4gcGFydGljdWxhciwgd2UgZG8gbm90IGhhdmUgYW55IHBvbGx1dGlvbiBkYXRhIGZvciAyMDE0IG5vciBmb3IgTk8gaW4gMjAxNSBhbmQgdmVyeSBmZXcgb2JzZXJ2YXRpb25zIGZvciBQTXMgaW4gMjAxOS4gVGhlc2UgaXNzdWUgZG8gbm90IGNvbWUgZnJvbSBhY3R1YWwgbWlzc2luZyBkYXRhIGJ1dCBhcmUgZHVlIHRvIGlzc3VlIHdpdGggdGhlIHBhY2thZ2Ugd2UgdXNlZCB0byBhY2Nlc3MgdGhlIHBvbGx1dGlvbiBkYXRhLiBUaGVzZSBkYXRhIGFyZSBhdmFpbGFibGUgdGhyb3VnaCB0aGUgRUVBIGludGVyZmFjZS4KCmBgYHtyfQpkYXRhIDwtIGRhdGFfaW1wdXRhdGlvbiAlPiUgIAogIG11dGF0ZSgKICAgIHllYXIgPSBhcy5mYWN0b3IoeWVhcihkYXRlKSksCiAgICBtb250aCA9IGFzLmZhY3Rvcihtb250aChkYXRlKSksCiAgICBkYXlfb2ZfbW9udGggPSBhcy5mYWN0b3IoZGF5KGRhdGUpKSwKICAgIGRheV9pbl93ZWVrID0gYXMuZmFjdG9yKHdkYXkoZGF0ZSkpLAogICAgaG91ciA9IGFzLmZhY3Rvcihob3VyKGRhdGUpKSwKICAgIG1pc3NpbmcgPSBpcy5uYShjb25jZW50cmF0aW9uKQogICkgJT4lIAogIGZpbHRlcih5ZWFyICE9IDIwMTQpICU+JSAKICBmaWx0ZXIoISh5ZWFyID09IDIwMTUgJiBwb2xsdXRhbnQgPT0gIm5vIikpICU+JSAKICBmaWx0ZXIoISh5ZWFyID09IDIwMTkgJiBzdHJfc3ViKHBvbGx1dGFudCwgMSwgMikgPT0gInBtIikpIAogIAogIApybShkYXRhX2ltcHV0YXRpb24pCmBgYAoKCiMgU2hhcmUgb2YgbWlzc2luZyBkYXRhIGluIGNvdmFyaWF0ZXMKCmBgYHtyfQpkYXRhICU+JSAKICBzZWxlY3QoLShwb2xsdXRhbnQ6YXZlcmFnaW5nX3RpbWUpLCAtY29uY2VudHJhdGlvbiwgLSh5ZWFyOmhvdXIpKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgc3VtbWFyaXNlX2FsbChmdW5jdGlvbih4KSB7c3VtKGlzLm5hKHgpLCBuYS5ybSA9IFRSVUUpL24oKX0pICU+JSAKICBwaXZvdF9sb25nZXIoZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJ2YXJpYWJsZV9uYW1lIiwgdmFsdWVzX3RvID0gInByb3BfbWlzc2luZyIpICU+JQogIG11dGF0ZSh2YXJpYWJsZV9uYW1lID0gc3RyX3JlcGxhY2VfYWxsKHZhcmlhYmxlX25hbWUsIHBhdHRlcm4gPSAiXyIsIHJlcGxhY2VtZW50ID0gIiAiKSAlPiUgc3RyX3RvX3NlbnRlbmNlKCkpICU+JSAKICBrYWJsZShjb2wubmFtZXMgPSBjKCJWYXJpYWJsZSIsICJQcm9wb3J0aW9uIG9mIG1pc3NpbmcgdmFsdWVzIikpCmBgYAoKSW4gb3JkZXIgdG8gdW5kZXJzdGFuZCB0aGVzZSBwcmV2aW91cyByZXN1bHRzLCB3ZSBicmVhayBkb3duIHRoZSBhbmFseXNpcyBieSB5ZWFyIGFuZCByZXByZXNlbnQgdGhlIHJlc3VsdHMgaW4gYSBncmFwaCwgZm9yIHJlYWRhYmlsaXR5LgoKYGBge3J9CmNvdmFyX21pc3NpbmdfeWVhciA8LSBkYXRhICU+JSAKICAjIHNsaWNlKDE6MTAwMDApICU+JQogIHNlbGVjdCgtKHBvbGx1dGFudDphdmVyYWdpbmdfdGltZSksIC1jb25jZW50cmF0aW9uLCAtKG1vbnRoOmhvdXIpKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgZ3JvdXBfYnkoeWVhcikgJT4lIAogICMgbXV0YXRlX2FsbChpcy5uYSkgJT4lIAogIHN1bW1hcmlzZV9hbGwoZnVuY3Rpb24oeCkge3N1bShpcy5uYSh4KSwgbmEucm0gPSBUUlVFKS9uKCl9KSAlPiUKICBwaXZvdF9sb25nZXIoMjpsYXN0X2NvbCgpLCBuYW1lc190byA9ICJ2YXJpYWJsZV9uYW1lIiwgdmFsdWVzX3RvID0gInByb3BfbWlzc2luZyIpCgpjb3Zhcl9taXNzaW5nX3llYXIgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fY29sKGFlcyh4ID0gdmFyaWFibGVfbmFtZSwgIHkgPSBwcm9wX21pc3NpbmcsIGZpbGwgPSB5ZWFyKSwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIlByb3BvcnRpb24gb2YgbWlzc2luZyBkYXRhIGJ5IGNvdmFyaWF0ZSIsIHN1YnRpdGxlID0gIkJ5IHllYXIiLCB5ID0gIlByb3BvcnRpb24gb2YgbWlzc2luZyBkYXRhIiwgeCA9ICIiKQpgYGAKCkluIGNvbXBsZXRlIGNhc2UgYW5hbHlzZXMsIG9ic2VydmF0aW9ucyBmb3Igd2hpY2ggYW55IHZhcmlhYmxlIGlzIG1pc3NpbmcgYXJlIGRyb3BwZWQuIE9uZSBtYXkgdGhlcmVmb3JlIHdvbmRlciB3aGF0IGlzIHRoZSBzaGFyZSBvZiBkcm9wcGVkIG9ic2VydmF0aW9ucyBpbiBhIGNvbXBsZXRlIGNhc2UgYW5hbHlzaXMuIFdlIG9ubHkgY29uc2lkZXIgdmFyaWFibGVzIHdoaWNoIGFyZSBwb3RlbnRpYWxseSByZWxldmFudC4gV2UgYWxzbyBkcm9wIHRoZSBVViByYWRpYXRpb24gdmFyaWFibGUgZHVlIHRvIGl0cyBsYXJnZSBzaGFyZSBvZiBtaXNzaW5nbmVzcy4KCmBgYHtyIGluY2x1ZGU9RkFMU0V9CmFueV9taXNzaW5nX2NvdiA8LSBkYXRhICU+JSAKICBzZWxlY3QoZWxldmF0aW9uOnB1YmxpY19ob2xpZGF5LCAtbGF0aXR1ZGVfd2VhdGhlcl9zdGF0aW9uLCAtbG9uZ2l0dWRlX3dlYXRoZXJfc3RhdGlvbiwgLXV2X3JhZGlhdGlvbikgJT4lIAogIG11dGF0ZV9hbGwoaXMubmEpICU+JSAKICB0cmFuc211dGUoYW55X21pc3NpbmcgPSAocm93U3VtcyguKSA+IDApKSAlPiUgCiAgLiRhbnlfbWlzc2luZwoKcHJvcF9jb3Zhcl9taXNzaW5nIDwtIHN1bShhbnlfbWlzc2luZ19jb3YpL2xlbmd0aChhbnlfbWlzc2luZ19jb3YpCgpwcm9wX3RvdGFsX21pc3NpbmcgPC0gc3VtKGFueV9taXNzaW5nX2NvdiArIGRhdGEkbWlzc2luZykvbGVuZ3RoKGFueV9taXNzaW5nX2NvdikKYGBgCgpDYXJyeWluZyBvdXQgYSBjb21wbGV0ZSBjYXNlIGFuYWx5c2lzIHdvdWxkIGxlYWQgdG8gZHJvcCBgciBwcm9wX3RvdGFsX21pc3NpbmcqMTAwYCUgb2YgdGhlIG9ic2VydmF0aW9ucy4gT25seSBjb25zaWRlcmluZyBtaXNzaW5nIGNvdmFyaWF0ZXMgKGFuZCBub3QgbWlzc2luZ25lc3MgaW4gY29uY2VudHJhdGlvbiBkYXRhKSB3b3VsZCBsZWFkIHRvIGRyb3AgYHIgcHJvcF9jb3Zhcl9taXNzaW5nKjEwMGAlIG9mIHRoZSBvYnNlcnZhdGlvbnMuCgojIExvY2F0aW9uIG9mIG1lYXN1cmVtZW50IHN0YXRpb25zCgpUaGUgc3RhdGlvbnMgY29uc2lkZXJlZCBhcmUgbG9jYXRlZCBpbiB0aGUgMTcgYmlnZ2VzdCBsYXJnZXN0IGluIEZyYW5jZToKCmBgYHtyfQptZXRhZGF0YV9wb2xsdXRpb24gJT4lIAogIGNvdW50KGNpdHkpICU+JSAKICBrYWJsZShjb2wubmFtZXMgPSBjKCJDaXR5IiwgIk51bWJlciBvZiBzdGF0aW9ucyIpKQpgYGAKCiMgTWlzc2luZyBkYXRhIHBhdHRlcm5zIGluIGFpciBwb2xsdXRpb24gZGF0YQoKSGVyZSwgd2UgaW52ZXN0aWdhdGUgd2hldGhlciBtaXNzaW5nIHBvbGx1dGFudCBjb25jZW50cmF0aW9uIGRhdGEgdmFyaWVzIGFjcm9zcyBkaWZmZXJlbnQgZGltZW50aW9ucy4gCgpgYGB7ciBpbmNsdWRlID0gRkFMU0V9CnNoYXJlX21pc3NpbmcgPC0gc3VtKGlzLm5hKGRhdGEkY29uY2VudHJhdGlvbikpL25yb3coZGF0YSkKYGBgCgpUaGUgb3ZlcmFsbCBzaGFyZSBvZiBtaXNzaW5nIHZhbHVlcyBpcyBgciBzaGFyZV9taXNzaW5nYC4KCiMjIEJhbGFuY2UgZ3JhaHMKCndlIGZpcnN0IGludmVzdGlnYXRlIHdoZXRoZXIgY292YXJpYXRlcyBhcmUgYmFsbGFuY2VkIGJldHdlZW4gb2JzZXJ2YXRpb25zIGZvciB3aGljaCBjb25jZW50cmF0aW9uIGRhdGEgaXMgbWlzc2luZyBhbmQgbm9uIG1pc3NpbmcuIAoKYGBge3J9CmRhdGFfY2xlYW5fY29udGludW91cyA8LSBkYXRhICU+JQogIHNlbGVjdChlbGV2YXRpb246ZWxldmF0aW9uX3dlYXRoZXJfc3RhdGlvbiwgcmFpbmZhbGxfaGVpZ2h0OnNjaG9vbF9ob2xpZGF5LCBtaXNzaW5nKQoKIyB3ZSBjb21wdXRlIHRoZSBhYnNvbHV0ZSBkaWZmZXJlbmNlIGJldHdlZW4gbm9uLW1pc3NpbmcgYW5kIG1pc3Npbmcgb2JzZXJ2YXRpb25zCmRhdGFfYWJzX2RpZmZlcmVuY2UgPC0gZGF0YV9jbGVhbl9jb250aW51b3VzICU+JQogIGdyb3VwX2J5KG1pc3NpbmcpICU+JQogIHN1bW1hcmlzZV9hbGwoLiwgfiBtZWFuKC4sIG5hLnJtID0gVFJVRSkpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLWMobWlzc2luZyksIG5hbWVzX3RvID0gInZhcmlhYmxlIiwgdmFsdWVzX3RvID0gImF2ZXJhZ2UiKSAlPiUKICBhcnJhbmdlKHZhcmlhYmxlKSAlPiUKICBncm91cF9ieSh2YXJpYWJsZSkgJT4lCiAgc3VtbWFyaXNlKGFic19kaWZmZXJlbmNlID0gYWJzKGF2ZXJhZ2VbMl0gLSBhdmVyYWdlWzFdKSkKCiMgd2UgY29tcHV0ZSB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSBub24tbWlzc2luZyB2YXJpYWJsZXMKZGF0YV9zZCA8LSBkYXRhX2NsZWFuX2NvbnRpbnVvdXMgJT4lCiAgZmlsdGVyKG1pc3NpbmcgPT0gRkFMU0UpICU+JQogIHNlbGVjdCgtbWlzc2luZykgJT4lCiAgc3VtbWFyaXNlX2FsbCguLCB+IHNkKC4sIG5hLnJtID0gVFJVRSkpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJ2YXJpYWJsZSIsIHZhbHVlc190byA9ICJzZF9ub25fbWlzc2luZyIpCgojIHdlIGNyZWF0ZSB0aGUgZGF0YSBmb3IgdGhlIGxvdmUgcGxvdCA6IHdlIHNjYWxlIHRoZSBhYnNvbHV0ZSBkaWZmZXJlbmNlIGJ5IHRoZSBzZF9ub25fbWlzc2luZwpkYXRhX2Fic19kaWZmZXJlbmNlICU+JSAKICBsZWZ0X2pvaW4oZGF0YV9zZCwgYnkgPSBjKCJ2YXJpYWJsZSIpKSAlPiUKICBtdXRhdGUoc3RhbmRhcmRpemVkX2RpZmZlcmVuY2UgPSBhYnNfZGlmZmVyZW5jZS9zZF9ub25fbWlzc2luZykgJT4lCiAgc2VsZWN0KC1jKGFic19kaWZmZXJlbmNlLCBzZF9ub25fbWlzc2luZykpICU+JSAKICBmaWx0ZXIoIWlzLm5hKHN0YW5kYXJkaXplZF9kaWZmZXJlbmNlKSkgJT4lIAogIGdncGxvdChhZXMoeSA9IGZjdF9yZXYodmFyaWFibGUpLCB4ID0gc3RhbmRhcmRpemVkX2RpZmZlcmVuY2UpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAuMSwgY29sb3IgPSAiI0ZBQjczNyIpICsKICBnZW9tX3BvaW50KCkgKwogICMgZmFjZXRfd3JhcCh+IGNpdHkpICsKICBsYWJzKHRpdGxlID0gIkNvdmFyaWF0ZSBiYWxhbmNlIiAsIHggPSAiU3RhbmRhcmRpemVkIE1lYW4gRGlmZmVyZW5jZXMiLCB5ID0gIiIpCgpgYGAKCkl0IHNlZW1zIHRoYXQgbW9zdCB3ZWF0aGVyIGNvdmFyaWF0ZXMgYXJlIGJhbGFuY2VkIGJldHdlZW4gdGhlIHR3byBncm91cHMuIEF2ZXJhZ2UgdGVtcGVyYXR1cmUgYW5kIFVWIHJhZGlhdGlvbiBtYXkgaG93ZXZlciBiZSBzbGlnaHRseSBkaWZmZXJlbnQgYmV0d2VlbiB0aGUgdHdvIGdyb3Vwcy4KCldlIGNhbiByZWZpbmUgdGhpcyBhbmFseXNpcyBieSBsb29raW5nIHNlcGFyYXRlbHkgYWNyb3NzIGNpdGllcy4KCmBgYHtyfQpkYXRhX2NsZWFuX2NvbnRpbnVvdXMgPC0gZGF0YSAlPiUKICBzZWxlY3QoZWxldmF0aW9uOmVsZXZhdGlvbl93ZWF0aGVyX3N0YXRpb24sIHJhaW5mYWxsX2hlaWdodDpzY2hvb2xfaG9saWRheSwgbWlzc2luZywgY2l0eSkKCiMgd2UgY29tcHV0ZSB0aGUgYWJzb2x1dGUgZGlmZmVyZW5jZSBiZXR3ZWVuIG5vbi1taXNzaW5nIGFuZCBtaXNzaW5nIG9ic2VydmF0aW9ucwpkYXRhX2Fic19kaWZmZXJlbmNlIDwtIGRhdGFfY2xlYW5fY29udGludW91cyAlPiUKICBncm91cF9ieShjaXR5LCBtaXNzaW5nKSAlPiUKICBzdW1tYXJpc2VfYWxsKC4sIH4gbWVhbiguLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jKGNpdHksIG1pc3NpbmcpLCBuYW1lc190byA9ICJ2YXJpYWJsZSIsIHZhbHVlc190byA9ICJhdmVyYWdlIikgJT4lCiAgYXJyYW5nZShjaXR5LCB2YXJpYWJsZSkgJT4lCiAgZ3JvdXBfYnkoY2l0eSwgdmFyaWFibGUpICU+JQogIHN1bW1hcmlzZShhYnNfZGlmZmVyZW5jZSA9IGFicyhhdmVyYWdlWzJdIC0gYXZlcmFnZVsxXSkpCgojIHdlIGNvbXB1dGUgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgbm9uLW1pc3NpbmcgdmFyaWFibGVzCmRhdGFfc2QgPC0gZGF0YV9jbGVhbl9jb250aW51b3VzICU+JQogIGZpbHRlcihtaXNzaW5nID09IEZBTFNFKSAlPiUKICBzZWxlY3QoLW1pc3NpbmcpICU+JQogIGdyb3VwX2J5KGNpdHkpICU+JQogIHN1bW1hcmlzZV9hbGwoLiwgfiBzZCguLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jKGNpdHkpLCBuYW1lc190byA9ICJ2YXJpYWJsZSIsIHZhbHVlc190byA9ICJzZF9ub25fbWlzc2luZyIpCgojIHdlIGNyZWF0ZSB0aGUgZGF0YSBmb3IgdGhlIGxvdmUgcGxvdCA6IHdlIHNjYWxlIHRoZSBhYnNvbHV0ZSBkaWZmZXJlbmNlIGJ5IHRoZSBzZF9ub25fbWlzc2luZwpkYXRhX2Fic19kaWZmZXJlbmNlICU+JSAKICBsZWZ0X2pvaW4oZGF0YV9zZCwgYnkgPSBjKCJjaXR5IiwgInZhcmlhYmxlIikpICU+JQogIG11dGF0ZShzdGFuZGFyZGl6ZWRfZGlmZmVyZW5jZSA9IGFic19kaWZmZXJlbmNlL3NkX25vbl9taXNzaW5nKSAlPiUKICBzZWxlY3QoLWMoYWJzX2RpZmZlcmVuY2UsIHNkX25vbl9taXNzaW5nKSkgJT4lIAogIGZpbHRlcighaXMubmEoc3RhbmRhcmRpemVkX2RpZmZlcmVuY2UpKSAlPiUgCiAgZ2dwbG90KGFlcyh5ID0gZmN0X3Jldih2YXJpYWJsZSksIHggPSBzdGFuZGFyZGl6ZWRfZGlmZmVyZW5jZSkpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC4xLCBjb2xvciA9ICIjRkFCNzM3IikgKwogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfd3JhcCh+IGNpdHkpICsKICBsYWJzKHRpdGxlID0gIkNvdmFyaWF0ZSBiYWxhbmNlIiAsIHggPSAiU3RhbmRhcmRpemVkIE1lYW4gRGlmZmVyZW5jZXMiLCB5ID0gIiIpCgpgYGAKCiMjIEV2b2x1dGlvbiBvZiB0aGUgc2hhcmUgb2YgbWlzc2luZyB2YWx1ZXMgd2l0aCB0aGUgdmFsdWVzIG9mIGNvdmFyaWF0ZXMKCkluIHRoaXMgc2VjdGlvbiwgd2UgaW52ZXN0aWdhdGUgd2hldGhlciB0aGUgc2hhcmUgb2YgbWlzc2luZyB2YWx1ZXMgdmFyaWVzIHdpdGggdGhlIHZhbHVlcyBvZiBjb3ZhcmlhdGVzLiBPbmUgbWF5IGV4cGVjdCB0aGF0LCBmb3IgZXh0cmVtZSB2YWx1ZXMgb2Ygc29tZSBjb3ZhcmlhdGVzLCBzdWNoIGFzIHRlbXBlcmF0dXJlLCB3aW5kIHNwZWVkIG9yIHByZWNpcGl0YXRpb24gbGV2ZWwgZm9yIGV4YW1wbGUsIG1lYXN1cmVtZW50IGluc3RydW1lbnRzIGFyZSBtb3JlIGxpa2VseSB0byBiZSBkZWZlY3RpdmUsIGxlYWRpbmcgdG8gbW9yZSBtaXNzaW5nIHZhbHVlcy4KCgpgYGB7cn0KIycgR3JhcGhzIGRlc2NyaWJpbmcgdGhlIHByb3BvcnRpb24gb2YgbWlzc2luZyB2YWx1ZXMgaW4gZGlmZmVyZW50IGdyb3VwcwojJwojJyBFbmFibGVzIHRvIHBsb3QgdGhlIHByb3BvcnRpb24gb2YgbWlzc2luZyB2YWx1ZXMgYnkgYSBudW1iZXIgb2YgCiMnCiMnIEBwYXJhbSBkZiBBIGRhdGFmcmFtZS4gRGF0YWZyYW1lIHRvIGFuYWx5c2UgCiMnIEBwYXJhbSBncm91cGluZ192YXIgQSBzdHJpbmcuIE5hbWUgb2YgdGhlIHZhcmlhYmxlLCBpbiBcY29kZXtkZn0sIGZvciB3aGljaCB0aGUgcHJvcG9ydGlvbiBvZiBtaXNzaW5nIHZhbHVlcyBuZWVkcyB0byBiZSBkaXNwbGF5ZWQKIycgQHBhcmFtIGJpbnMgQW4gaW50ZWdlci4gTnVtYmVyIG9mIGJpbnMgdG8gc2xpY2UgXGNvZGV7Z3JvdXBpbmdfdmFyfSBpbiwgaWYgaXQgaXMgYSBjb250aW51b3VzIHZhbHVlLgojJyBAcGFyYW0gZmFjZXRfdmFyIEEgc3RyaW5nLiBOYW1lIG9mIHRoZSB2YXJpYWJsZSwgaW4gXGNvZGV7ZGZ9LCBieSB3aGljaCB0byBmYWNldCB0aGUgaW5pdGlhbCBncmFwaAojJyBAcGFyYW0geV9heGlzX3RvIEFuIGludGVnZXIuIExpbWl0IG9mIHRoZSB5IGF4aXMKIycgQGV4cG9ydAojJwpoaXN0X21pc3NpbmdfYnkgPC0gZnVuY3Rpb24oZGYsIHZhcmlhYmxlX21pc3NpbmcgPSAiY29uY2VudHJhdGlvbiIsIGdyb3VwaW5nX3ZhciwgYmlucyA9IDE1LCBmYWNldF92YXIgPSBOQSwgZmlsbF92YXIgPSBOQSwgeV9heGlzX3RvID0gMC4zKSB7CiAgCiAgZ3JvdXBpbmdfdmFyX25hbWUgPC0gc3RyX3JlcGxhY2VfYWxsKGdyb3VwaW5nX3ZhciwgcGF0dGVybiA9ICJfIiwgcmVwbGFjZW1lbnQgPSAiICIpCiAgdmFyaWFibGVfbWlzc2luZ19uYW1lIDwtIHN0cl9yZXBsYWNlX2FsbCh2YXJpYWJsZV9taXNzaW5nLCBwYXR0ZXJuID0gIl8iLCByZXBsYWNlbWVudCA9ICIgIikKICAKICBpZiAoIWlzLmZhY3RvcihkZltbZ3JvdXBpbmdfdmFyXV0pICYmICFpcy5sb2dpY2FsKGRmW1tncm91cGluZ192YXJdXSkgICYmICFpcy5uYShhcy5udW1lcmljKGRmW1tncm91cGluZ192YXJdXSkpKSB7CiAgICBkZltbZ3JvdXBpbmdfdmFyXV0gPC0gY3V0X2ludGVydmFsKGFzLm51bWVyaWMoZGZbW2dyb3VwaW5nX3Zhcl1dKSwgYmlucykKICB9IAogIAogIGdyYXBoIDwtIGRmICU+JSAKICAgIGZpbHRlcighaXMubmEoLmRhdGFbW2dyb3VwaW5nX3Zhcl1dKSkgJT4lIAogICAgZ3JvdXBfYnlfKGdyb3VwaW5nX3ZhciwgZmFjZXRfdmFyLCBmaWxsX3ZhcikgJT4lCiAgICBzdW1tYXJpc2Uoc2hhcmVfbWlzc2luZyA9IHN1bShpcy5uYSguZGF0YVtbdmFyaWFibGVfbWlzc2luZ11dKSkvbigpKSAlPiUKICAgIGFycmFuZ2Uoc2hhcmVfbWlzc2luZykgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSAuZGF0YVtbZ3JvdXBpbmdfdmFyXV0sIHkgPSBzaGFyZV9taXNzaW5nKSkgKwogICAgZ2VvbV9jb2woYWVzX3N0cmluZyhmaWxsID0gaWZlbHNlKCFpcy5uYShmaWxsX3ZhciksIGZpbGxfdmFyLCAiTlVMTCIpKSwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgICBsYWJzKAogICAgICB0aXRsZSA9IHBhc3RlKCJTaGFyZSBvZiBtaXNzaW5nIiwgdmFyaWFibGVfbWlzc2luZ19uYW1lLCJkYXRhIGJ5IiwgZ3JvdXBpbmdfdmFyX25hbWUpLAogICAgICB4ID0gc3RyX3RvX3NlbnRlbmNlKGdyb3VwaW5nX3Zhcl9uYW1lKSwgCiAgICAgIHkgPSBwYXN0ZSgiU2hhcmUgb2YgbWlzc2luZyIsIHZhcmlhYmxlX21pc3NpbmdfbmFtZSwiZGF0YSIpCiAgICApIAogIAogIGlmICghaXMubnVsbCh5X2F4aXNfdG8pKSB7CiAgICBncmFwaCA8LSBncmFwaCArIAogICAgICB5bGltKDAsIHlfYXhpc190bykgCiAgfQogICAKICBpZiAoIWlzLm5hKGZhY2V0X3ZhcikpIHsKICAgIGdyYXBoIDwtIGdyYXBoICsKICAgIGZhY2V0X3dyYXAoZmFjZXRzID0gZmFjZXRfdmFyKQogIH0gCiAgCiAgaWYgKHN1YnN0cihncm91cGluZ192YXIsIDEsIDgpID09ICJ3aW5kX2RpciIpIHsKICAgIGdyYXBoIDwtIGdyYXBoICsKICAgICAgY29vcmRfcG9sYXIoKSArIAogICAgICB5bGltKDAsIDAuMSkgCiAgfQogIAogIAogIHJldHVybihncmFwaCkKfQpgYGAKCiMjIyBBY3Jvc3MgcG9sbHV0YW50cwoKYGBge3J9CmRhdGEgJT4lICAKICBoaXN0X21pc3NpbmdfYnkoZ3JvdXBpbmdfdmFyID0gInBvbGx1dGFudCIpIApgYGAKCk9uZSBjYW4gbm90aWNlIHRoYXQgdGhlIHNoYXJlIG9mIG1pc3NpbmcgdmFsdWVzIHZhcmllcyBhY3Jvc3MgcG9sbHV0YW50cywgdXAgdG8gYWJvdXQgYSBmYWN0b3IgdHdvLiBUaGlzIGhpZ2xpZ2h0cyB0aGUgcG90ZW50aWFsIG5lY2Vzc2l0eSBvZiBhbmFseXNpbmcgbWlzc2luZ25lc3MgcGF0dGVybnMgaW5kZXBlbmRlbnRseSBhY3Jvc3MgcG9sbHV0YW50cy4KCiMjIyBBY3Jvc3MgbG9jYXRpb25zCgpXZSBsb29rIHdlYXRoZXIgbWlzc2luZ25lc3MgcGF0dGVybnMgdmFyeSBhY3Jvc3MgbG9jYXRpb24gY2hhcmFjdGVyaXN0aWNzLgoKYGBge3J9CmNvdmFyaWF0ZXNfbG9jYXRpb24gPC0gZGF0YSAlPiUgCiAgc2VsZWN0KGVsZXZhdGlvbjplbGV2YXRpb25fd2VhdGhlcl9zdGF0aW9uKSAlPiUgCiAgbmFtZXMoKQoKcHVycnI6Om1hcChjb3ZhcmlhdGVzX2xvY2F0aW9uLCBoaXN0X21pc3NpbmdfYnksIGRmID0gZGF0YSwgdmFyaWFibGVfbWlzc2luZyA9ICJjb25jZW50cmF0aW9uIiwgYmlucyA9IDEwLCBmYWNldF92YXIgPSBOQSwgZmlsbCA9IE5BLCB5X2F4aXNfdG8gPSAwLjMpCgpkYXRhICU+JQogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAiY2l0eSIpICsKICBjb29yZF9mbGlwKCkKYGBgCgojIyMgQWNyb3NzIGRhdGVzIGFuZCB0aW1lCgpXZSB0aGVuIGludmVzdGlnYXRlIHdoZXRoZXIgdGhlIHNoYXJlIG9mIG1pc3NpbmcgdmFsdWVzIGV2b2x2ZXMgd2l0aCBkYXRlcyBhbmQgdGltZS4KCmBgYHtyfQpjb3ZhcmlhdGVzX3RpbWUgPC0gZGF0YSAlPiUgCiAgc2VsZWN0KHB1YmxpY19ob2xpZGF5OmhvdXIpICU+JSAKICBuYW1lcygpCgpwdXJycjo6bWFwKGNvdmFyaWF0ZXNfdGltZSwgaGlzdF9taXNzaW5nX2J5LCBkZiA9IGRhdGEsIHZhcmlhYmxlX21pc3NpbmcgPSAiY29uY2VudHJhdGlvbiIsIGJpbnMgPSAxNSwgZmFjZXRfdmFyID0gTkEsIGZpbGwgPSBOQSwgeV9heGlzX3RvID0gMC4zKQpgYGAKCk92ZXJhbGwsIHdlIG5vdGljZSB0aGF0LCBhbG9uZyB0aGUgdGltZSBkaW1lbnNpb24gZGF0YSBhbG1vc3Qgc2VlbXMgdG8gYmUgbWlzc2luZyBhdCByYW5kb20gYXBwYXJ0IGZyb20gYSBkZWNyZWFzaW5nIHRyZW5kIGluIHRoZSBwcm9wb3J0aW9uIG9mIG1pc3NpbmcgZGF0YSAKCldlIGFsc28gZXhwbG9yZSBtb3JlIGNsb3NlbHkgdGhlc2UgcGF0dGVybnMgZm9yIHNvbWUgdmFyaWFibGVzIGJ5IGRlY29tcG9zaW5nIHRoZW0gYnkgeWVhciwgbW9udGggb3IgcG9sbHV0YW50LgoKYGBge3J9CmRhdGEgJT4lICAKICBoaXN0X21pc3NpbmdfYnkoZ3JvdXBpbmdfdmFyID0gIm1vbnRoIiwgZmFjZXRfdmFyID0gInllYXIiKQoKZGF0YSAlPiUgIAogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAiZGF5X29mX21vbnRoIiwgZmFjZXRfdmFyID0gInllYXIiKQoKZGF0YSAlPiUgIAogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAiZGF5X29mX21vbnRoIiwgZmFjZXRfdmFyID0gIm1vbnRoIikKCmRhdGEgJT4lCiAgaGlzdF9taXNzaW5nX2J5KGdyb3VwaW5nX3ZhciA9ICJkYXlfaW5fd2VlayIsIGZhY2V0X3ZhciA9ICJ5ZWFyIikKCmRhdGEgJT4lCiAgaGlzdF9taXNzaW5nX2J5KGdyb3VwaW5nX3ZhciA9ICJkYXlfaW5fd2VlayIsIGZhY2V0X3ZhciA9ICJtb250aCIpCgpkYXRhICU+JQogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAiaG91ciIsIGZhY2V0X3ZhciA9ICJwb2xsdXRhbnQiKQoKZGF0YSAlPiUKICBoaXN0X21pc3NpbmdfYnkoZ3JvdXBpbmdfdmFyID0gInllYXIiLCBmaWxsX3ZhciA9ICJwb2xsdXRhbnQiKQpgYGAKCiMjIyBBY3Jvc3Mgd2VhdGhlciB2YXJpYWJsZXMKCmBgYHtyfQpjb3ZhcmlhdGVzX3dlYXRoZXIgPC0gZGF0YSAlPiUgCiAgc2VsZWN0KHJhaW5mYWxsX2hlaWdodDp1dl9yYWRpYXRpb24pICU+JSAKICBuYW1lcygpCgpwdXJycjo6bWFwKGNvdmFyaWF0ZXNfd2VhdGhlciwgaGlzdF9taXNzaW5nX2J5LCBkZiA9IGRhdGEsIHZhcmlhYmxlX21pc3NpbmcgPSAiY29uY2VudHJhdGlvbiIsIGJpbnMgPSAxNSwgZmFjZXRfdmFyID0gTkEsIGZpbGwgPSBOQSwgeV9heGlzX3RvID0gMC4zKQpgYGAKCgojIyMgT25seSBjb25zaWRlciBmaXJzdCBtaXNzaW5nIHZhbHVlCgpJZiBkYXRhIGlzIG1pc3NpbmcgZHVlIHRvIGV4dGVybmFsIGZhY3RvcnMsIHdoYXQgbWF0dGVycyBtaWdodCBiZSB0aGUgdmFsdWUgb2YgdGhlc2UgZXh0ZXJuYWwgZmFjdG9yIHdoZW4gdGhlIGRhdGEgc3RhcnRlZCBtaXNzaW5nLCAqaWUqIHBvdGVudGlhbGx5IHdoZW4gdGhlIHNlbnNvciBmaXJzdCBiZWNhbWUgZGVmZWN0aXZlLiBBcyBhIGNvbnNlcXVlbmNlLCB3ZSBwbG90IHRoZSBzYW1lIGdyYXBocyBhcyBiZWZvcmUgYnV0IG9ubHkgY29uc2lkZXJpbmcgaG91cnMgd2VyZSB0aGUgZGF0YSBzdGFydGVkIG1pc3NpbmcsIG5vdCBjb25zaWRlcmluZyBsYXRlciBhbmQgY29uc2VjdXRpdmUgbWlzc2luZyBvYnNlcnZhdGlvbnMuCgpBcyBjb21wYXJlZCB0byB0aGUgZnVsbCBzYW1wbGUsIHRoZSBzaGFyZSBvZiBtaXNzaW5nIGRhdGEgZGVjcmVhc2VzIHNpbmNlIHdlIGRpc2NhcmRlZCBtYW55IG9ic2VydmF0aW9ucyB3aXRoIG1pc3NpbmcgdmFsdWVzIChldmVyeSBvYnNlcnZhdGlvbiB3aGljaCB3YXMgbm90IHRoZSBmaXJzdCBvYnNlcnZhdGlvbiBvZiB0aGVpciBwZXJpb2Qgb2YgbWlzc2luZyBkYXRhKS4gSGVuY2UsIHRoZSBzaGFyZSBvZiBtaXNzaW5nIGRhdGEgaXMgbm90IGluZm9ybWF0aXZlIGluIGl0c2VsZiwgb25seSBwb3RlbnRpYWwgZGlmZmVyZW5jZXMgaW4gdGhpcyBzaGFyZSBhY3Jvc3MgImdyb3VwaW5nIHZhcmlhYmxlcyIuCgpgYGB7cn0KZGF0YV9maXJzdF9taXNzaW5nIDwtIGRhdGEgJT4lICAKICBncm91cF9ieShzaXRlLCBwb2xsdXRhbnQpICU+JQogIGFycmFuZ2UoZGF0ZSkgJT4lIAogIG11dGF0ZSggCiAgICBmaXJzdF9taXNzaW5nID0gaWZlbHNlKG1pc3NpbmcgPT0gVFJVRSAmIGxhZyhtaXNzaW5nKSA9PSBGQUxTRSwgVFJVRSwgRkFMU0UpCiAgKSAlPiUKICBmaWx0ZXIoZmlyc3RfbWlzc2luZyB8IG1pc3NpbmcgPT0gRkFMU0UpCmBgYAoKCmBgYHtyfQpjb3ZhcmlhdGVfbmFtZXMgPC0gZGF0YSAlPiUgCiAgc2VsZWN0KGNpdHksIHBvbGx1dGFudCwgZWxldmF0aW9uOmhvdXIsIC1lbmRzX3dpdGgoIndlYXRoZXJfc3RhdGlvbiIpKSAlPiUgCiAgbmFtZXMoKQoKcHVycnI6Om1hcChjb3ZhcmlhdGVfbmFtZXMsIGhpc3RfbWlzc2luZ19ieSwgZGYgPSBkYXRhX2ZpcnN0X21pc3NpbmcsIHZhcmlhYmxlX21pc3NpbmcgPSAiY29uY2VudHJhdGlvbiIsIGJpbnMgPSAxMCwgZmFjZXRfdmFyID0gTkEsIHlfYXhpc190byA9IDAuMSkKYGBgCgojIyBTaW11bHRhbmVvdXMgbWlzc2luZ25lc3MKCkluIHRoaXMgc2VjdGlvbiwgd2UgYW5hbHlzZSB3aGV0aGVyIHNvbWUgcGF0dGVybnMgb2Ygc2ltdWx0YW5lb3VzIG1pc3NpbmduZXNzIGFwcGVhciBpbiB0aGUgZGF0YS4gV2Ugd29uZGVyIHdoZXRoZXIsIGZvciBhIGdpdmVuIHN0YXRpb24sIGRhdGEgaXMgc2ltdWx0YW5lb3VzbHkgbWlzc2luZyBmb3Igc2V2ZXJhbCBwb2xsdXRhbnRzIG9yIHdoZXRoZXIsIGZvciBhIGdpdmVuIGNpdHksIGRhdGEgaXMgc2ltdWx0YW5lb3VzbHkgbWlzc2luZyBmb3Igc2V2ZXJhbCBzdGF0aW9ucy4gCgojIyMgQWNyb3NzIHBvbGx1dGFudHMKCldlIGludmVzdGlnYXRlIHdoZXRoZXIsIGluIGEgZ2l2ZW4gc3RhdGlvbiwgd2hlbiBvbmUgcG9sbHV0YW50IGlzIG1pc3NpbmcsIG90aGVyIHBvbGx1dGFudHMgYXJlIGFsc28gbWlzc2luZy4gU3VjaCBhIG1pc3NpbmduZXNzIHBhdHRlcm4gY291bGQgYXJpc2UgaWYgc2Vuc29ycyBmb3IgZGlmZmVyZW50IHBvbGx1dGFudHMgZnVuY3Rpb24gam9pbnRseS4gCgpXZSBjb3VudCB0aGUgbnVtYmVyIG9mIHBvbGx1dGFudHMgd2hpY2ggYXJlIHNpbXVsdGFuZW91c2x5IG1pc3NpbmcgZm9yIGV2ZXJ5IHN0YXRpb24qZGF0ZSBjb3VwbGUuIE5vdGUgdGhhdCB0aGlzIGFuYWx5c2lzIGRvZXMgbm90IGNvbnNpZGVyIHRoYXQgYW4gb2JzZXJ2YXRpb24gaXMgbWlzc2luZyB3aGVuIGEgZ2l2ZW4gc3RhdGlvbiBpcyBjbG9zZWQgZm9yIGEgcG9sbHV0YW50LgoKYGBge3J9CmRhdGEgJT4lIAogIGdyb3VwX2J5KGRhdGUsIHNpdGUpICU+JSAKICBzdW1tYXJpc2UobmJfbWlzc2luZyA9IHN1bShtaXNzaW5nKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgY291bnQobmJfbWlzc2luZykgJT4lIAogIG11dGF0ZShwcm9wID0gbi9zdW0obikpICU+JSAKICBrYWJsZShjb2wubmFtZXMgPSBjKCJOdW1iZXIgb2YgcG9sbHV0YW50cyB3aXRoIG1pc3NpbmcgY29uY2VudHJhdGlvbiBkYXRhIiwgIk51bWJlciBvZiBkYXRlcyIsICJQcm9wb3J0aW9uIikpCmBgYAoKV2UgY291bGQgYWxzbyBpbnZlc3RpZ2F0ZSB3aGV0aGVyIHRoaXMgcGF0dGVybiB2YXJpZXMgd2l0aCB2YXJpb3VzIHdlYXRoZXIgdmFyaWFibGVzLgoKTm93LCBwYXJ0IG9mIHRoZSBzdGF0aW9ucyBkbyBub3QgbWVhc3VyZSB2YWx1ZXMgZm9yIGFsbCBwb2xsdXRhbnRzLiBUaHVzLCBpdCBpcyBpbnRlcmVzdGluZyB0byBjb21wdXRlIHRoZSBwcm9wb3J0aW9uIG9mIHBvbGx1dGFudHMgbWVhc3VyZWQgYnkgc3RhdGlvbiBmb3Igd2hpY2ggZGF0YSBpcyBtaXNzaW5nLgoKYGBge3J9CmRhdGEgJT4lIAogICMgbXV0YXRlKG9uZSA9IDEpICU+JSAKICBncm91cF9ieShkYXRlLCBzaXRlKSAlPiUgCiAgc3VtbWFyaXNlKHNoYXJlX21pc3NpbmcgPSBzdW0obWlzc2luZykvbigpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBjb3VudChzaGFyZV9taXNzaW5nKSAlPiUgCiAgbXV0YXRlKAogICAgcHJvcCA9IG4vc3VtKG4pLAogICAgcHJvcF9pZl9taXNzaW5nID0gaWZlbHNlKHNoYXJlX21pc3NpbmcgIT0gMCwgbi8oc3VtKG4pIC0gblsxXSksIE5BKQogICkgJT4lIAogIGthYmxlKGNvbC5uYW1lcyA9IGMoIlNoYXJlIG9mIHBvbGx1dGFudHMgbWVhc3VyZWQgaW4gdGhlIHN0YXRpb24gZm9yIHdoaWNoIGNvbmNlbnRyYXRpb24gZGF0YSBpcyBtaXNzaW5nIiwgIk51bWJlciBvZiBkYXRlcyIsICJQcm9wb3J0aW9uIiwgIlByb3BvcnRpb24gYW1vbmcgZGF0ZXMgd2l0aCBtaXNzaW5nIG9ic2VydmF0aW9ucyIpLCBjYXB0aW9uID0gIkluIGFsbCBzdGF0aW9ucyIpCmBgYAoKU2luY2UgZm9yIGFuYWx5c2VzIHN0dWR5aW5nIHRoZSBsaW5rIGJ0d2VlbiBhaXIgcG9sbHV0aW9uIGFuZCBoZWFsdGggaGF2ZSBhIHBhcnRpY3VsYXIgZm9jdXMgb24gYmFja2dyb3VuZCBzdGF0aW9uLCB3ZSBjYXJyeSBvdXQgdGhlIHNhbWUgYW5hbHlzaXMgZm9yIHRoZXNlIHN0YXRpb25zLgoKYGBge3J9CmRhdGEgJT4lIAogIGZpbHRlcihzaXRlX3R5cGUgPT0gImJhY2tncm91bmQiKSAlPiUgCiAgZ3JvdXBfYnkoZGF0ZSwgc2l0ZSkgJT4lIAogIHN1bW1hcmlzZShzaGFyZV9taXNzaW5nID0gc3VtKG1pc3NpbmcpL24oKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgY291bnQoc2hhcmVfbWlzc2luZykgJT4lIAogIG11dGF0ZSgKICAgIHByb3AgPSBuL3N1bShuKSwKICAgIHByb3BfaWZfbWlzc2luZyA9IGlmZWxzZShzaGFyZV9taXNzaW5nICE9IDAsIG4vKHN1bShuKSAtIG5bMV0pLCBOQSkKICApICU+JSAKICBrYWJsZShjb2wubmFtZXMgPSBjKCJTaGFyZSBvZiBwb2xsdXRhbnRzIG1lYXN1cmVkIGluIHRoZSBzdGF0aW9uIGZvciB3aGljaCBjb25jZW50cmF0aW9uIGRhdGEgaXMgbWlzc2luZyIsICJOdW1iZXIgb2YgZGF0ZXMiLCAiUHJvcG9ydGlvbiIsICJQcm9wb3J0aW9uIGFtb25nIGRhdGVzIHdpdGggbWlzc2luZyBvYnNlcnZhdGlvbnMiKSwgY2FwdGlvbiA9ICJPbmx5IGluIGJhY2tncm91bmQgc3RhdGlvbnMiKQpgYGAKCiMjIyBBY3Jvc3Mgc3RhdGlvbnMgaW4gYSBjaXR5CgpVbHRpbWF0ZWx5LCBhbmFseXNlcyBzdHVkeWluZyBoZWFsdGggZWZmZWN0cyBvZiBhaXIgcG9sbHV0aW9uIG9mdGVuIG9ubHkgdXNlIG9uZSBtZWFzdXJlIG9mIGNvbmNlbnRyYXRpb24gcGVyIGNpdHkgYW5kIHBlciBkYXRlLiBJbiBtb3N0IGNhc2VzLCB0aGVyZSBhcmUgc2V2ZXJhbCBhaXIgcG9sbHV0aW9uIG1lYXN1cmVtZW50IHN0YXRpb25zIHBlciBjaXR5LiBUbyBnZXQgYSB1bmlxdWUgbWVhc3VyZSBvZiBhaXIgcG9sbHV0aW9uIGZvciBhIGdpdmVuIGNpdHksIHRoZSBjb21tb24gcHJhY3RpY2UgY29uc2lzdHMgaW4gYXZlcmFnaW5nIHBvbGx1dGFudHMgY29uY2VudHJhdGlvbnMgZnJvbSBhbGwgYmFja2dyb3VuZCBzdGF0aW9ucyBpbiB0aGlzIGNpdHkuIFdlIG1heSB3b25kZXIgdG8gd2hhdCBleHRlbnQgY29uY2VudHJhdGlvbiBkYXRhIGlzIHNpbXVsdGFuZW91c2x5IG1pc3NpbmcgaW4gc2V2ZXJhbCBzdGF0aW9ucyBvZiBhIGdpdmVuIGNpdHkuIFdlIHRoZXJlZm9yZSBjb21wdXRlIHRoZSBhdmVyYWdlIHByb3BvcnRpb24gb2Ygc3RhdGlvbnMgcGVyIGNpdHkgaW4gd2hpY2ggZGF0YSBtaXNzaW5nLgoKYGBge3J9CmRhdGEgJT4lIAogIGZpbHRlcihzaXRlX3R5cGUgPT0gImJhY2tncm91bmQiKSAlPiUKICBncm91cF9ieShkYXRlLCBwb2xsdXRhbnQsIGNpdHkpICU+JSAKICBzdW1tYXJpc2Uoc2hhcmVfbWlzc2luZyA9IHN1bShtaXNzaW5nKS9uKCkpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGNvdW50KHNoYXJlX21pc3NpbmcpICU+JSAKICBtdXRhdGUoCiAgICBwcm9wID0gbi9zdW0obiksCiAgICBwcm9wX2lmX21pc3NpbmcgPSBpZmVsc2Uoc2hhcmVfbWlzc2luZyAhPSAwLCBuLyhzdW0obikgLSBuWzFdKSwgTkEpCiAgKSAlPiUgCiAga2FibGUoY29sLm5hbWVzID0gYygiU2hhcmUgb2Ygc3RhdGlvbnMgaW4gYSBjaXR5IGZvciB3aGljaCBjb25jZW50cmF0aW9uIGRhdGEgaXMgbWlzc2luZyIsICJOdW1iZXIgb2YgZGF0ZXMiLCAiUHJvcG9ydGlvbiIsICJQcm9wb3J0aW9uIGFtb25nIGRhdGVzIHdpdGggbWlzc2luZyBvYnNlcnZhdGlvbnMiKSwgY2FwdGlvbiA9ICJPbmx5IGluIGJhY2tncm91bmQgc3RhdGlvbnMiKQpgYGAKCgoKIyMgTGVuZ3RoIG9mIHBlcmlvZHMgd2l0aCBtaXNzaW5nIG9ic2VydmF0aW9ucwoKSW4gdGhpcyBzZWN0aW9uLCB3ZSBleHBsb3JlIHRoZSBsZW5ndGggb2YgcGVyaW9kcyB3aXRoIG1pc3Npbmcgb2JzZXJ2YXRpb25zLiBUaGlzIGxlbmd0aCBtYXkgcHJvdmlkZSBpbmZvcm1hdGlvbiBvbiBjYXVzZXMgb2YgbWlzc2luZ25lc3MuIE1pc3Npbmcgb2JzZXJ2YXRpb25zIGZvciBsb25nIHBlcmlvZHMgb2YgdGltZSBtYXkgYmUgaW5kaWNhdGl2ZSBvZiBjbHV0dGVyZWQgZmlsdGVycyBvZiBicm9rZW4gaW5zdHJ1bWVudC4gV2UgYWxzbyBleHBsb3JlIHdoZXRoZXIgdGhlIGxlbmd0aCBvZiBtaXNzaW5nbmVzcyBwYXR0ZXJucyBpcyBjb3JyZWxhdGVkIHdpdGggd2VhdGhlciB2YXJpYWJsZXMuCgpGaXJzdCwgd2UgZXhwbG9yZSB0aGUgbGVuZ3RoIG9mIG1pc3Npbmcgb2JzZXJ2YXRpb25zIGJ5IGxvb2tpbmcgYXQgdGhlIGRpc3BsYXlpbmcsIGluIGFuIGhlYXRtYXQsIGZvciBlYWNoIGNvdXBsZSBzdGF0aW9uKmRhdGUsIHdoZXRoZXIgY29uY2VudHJhdGlvbiBkYXRhIGlzIG1pc3NpbmcuIFdlIGJyZWFrIHRoaXMgZG93biBpbnRvIHllYXJzIGZvciByZWFkaWJpbGl0eS4gCgpgYGB7ciBoZWF0bWFwfQpoZWF0bWFwX21pc3NpbmduZXNzIDwtIGZ1bmN0aW9uKGRmLCB5KSB7CiAgCiAgZ3JhcGggPC0gZGYgJT4lIAogICAgZmlsdGVyKHllYXIgPT0geSkgJT4lIAogICAgZ3JvdXBfYnkoY2l0eSkgJT4lIAogICAgbXV0YXRlKHNpdGVfY2l0eSA9IHBhc3RlKGNpdHksIGFzLmludGVnZXIoZmFjdG9yKHNpdGUpKSwgc2VwID0gIl8iKSkgJT4lIAogICAgdW5ncm91cCgpICAlPiUKICAgIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSBzaXRlX2NpdHksIGZpbGwgPSBtaXNzaW5nKSkgKwogICAgZ2VvbV90aWxlKCkgKwogICAgIyB0aGVtZV9taW5pbWFsKCkgKwogICAgZmFjZXRfd3JhcCh+IHBvbGx1dGFudCkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzU4MEUzQyIsICIjRkFCNzM3IikpICsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgbGFicyh0aXRsZSA9IHBhc3RlKCJJbnRlcnZhbHMgd2l0aCBtaXNzaW5nIGNvbmNlbnRyYXRpb24gZGF0YSBwb2xsdXRhbnQgaW4iLCB5LCBzZXAgPSAiICIpLCB4ID0gIkRhdGUiLCB5ID0gICJBaXIgcG9sbHV0aW9uIHN0YXRpb24iKQogICAgCiAgcmV0dXJuKGdyYXBoKQp9CgpwdXJycjo6bWFwKGMoMjAxMywgMjAxNToyMDE5KSwgaGVhdG1hcF9taXNzaW5nbmVzcywgZGYgPSBkYXRhKQpgYGAKClRoZW4sIHdlIGxvb2sgYXQgdGhlIGxlbmd0aCBvZiBwZXJpb2RzIHdpdGggbWlzc2luZyBkYXRhLiBGaXJzdCwgd2UgY2FuIGVpdGhlciBjb3VudCBlYWNoIHRoZSBudW1iZXIgb2YgcGVyaW9kcyB3aXRoIGEgZ2l2ZW4gbGVuZ3RoICgqZWcqIDMgcGVyaW9kcyBoYXZlIGEgbGVuZ3RoIG9mIG1pc3NpbmcgZGF0YSBvZiA1IGhvdXJzKSBvciBjb3VudCB0aGUgbnVtYmVyIG9mIGRhdGVzIGJlbG9uZ2luZyB0byBwZXJpb2RzIHdpdGggYSBnaXZlbiBsZW5ndGggKGNvbnNpZGVyaW5nIHRoZSBzYW1lIGV4YW1wbGUsIDE1IGRhdGVzIGJlbG9uZyB0byBhIHBlcmlvZCBvZiBtaXNzaW5nIGRhdGEgb2YgbGVuZ3RoIDUgaG91cnMpLiBXZSBkZW5vdGUgdGhlIGZvcm1lciBjYXNlICJPbmUgb2JzZXJ2YXRpb24gcGVyIHBlcmlvZCIgYW5kIHRoZSBsYXRlciAiT25lIG9ic2VydmF0aW9uIHBlciBkYXRlIi4KCmBgYHtyfQojZ2l2ZSBlYWNoIG1pc3NpbmduZXNzIHBlcmlvZCBhbiBpZCAocm93X251bWJlciBvZiB0aGUgZmlyc3QgbWlzc2luZyBvYnNlcnZhdGlvbikKbGVuZ3RoX21pc3NpbmdfZGF0YSA8LSBkYXRhICU+JSAKICBtdXRhdGUocm93X2lkID0gcm93X251bWJlcigpKSAlPiUgCiAgZ3JvdXBfYnkoc2l0ZSwgcG9sbHV0YW50KSAlPiUKICBhcnJhbmdlKGRhdGUpICU+JSAKICBtdXRhdGUoCiAgICBtaXNzaW5nX3BlcmlvZF9pZCA9IGlmZWxzZShtaXNzaW5nID09IFRSVUUgJiBsYWcobWlzc2luZykgPT0gRkFMU0UsIHJvd19pZCwgTkEpCiAgKSAlPiUKICBmaWx0ZXIobWlzc2luZyA9PSBUUlVFKSAlPiUKICBmaWxsKG1pc3NpbmdfcGVyaW9kX2lkKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBzZWxlY3QoLXJvd19pZCkgJT4lIAogIGFycmFuZ2UobWlzc2luZ19wZXJpb2RfaWQpICU+JSAKICBncm91cF9ieShtaXNzaW5nX3BlcmlvZF9pZCwgcG9sbHV0YW50KSAlPiUgCiAgbXV0YXRlKGxlbmd0aF9wZXJpb2RfbWlzc2luZyA9IG4oKSkgJT4lIAogIHVuZ3JvdXAoKQoKbGVuZ3RoX21pc3Npbmdfb25lX3Blcl9wZXJpb2QgPC0gbGVuZ3RoX21pc3NpbmdfZGF0YSAlPiUgCiAgY291bnQobWlzc2luZ19wZXJpb2RfaWQsIHBvbGx1dGFudCwgbmFtZSA9ICJsZW5ndGhfcGVyaW9kX21pc3NpbmciKQpgYGAKCiMjIyBEaXN0cmlidXRpb24gb2YgbGVuZ3RocyBvZiBtaXNzaW5nIGRhdGEKCmBgYHtyfQpncmFwaF9kaXN0cmliX2xlbmd0aCA8LSBmdW5jdGlvbihkZiwgZGVuc2l0eSwgYmluc19hZGp1c3QpIHsKICBncmFwaCA8LSBkZiAlPiUgCiAgICBnZ3Bsb3QoYWVzKHggPSBsZW5ndGhfcGVyaW9kX21pc3NpbmcpKSAKICAKICBpZiAoZGVuc2l0eSkgewogICAgZ3JhcGggPC0gZ3JhcGggKwogICAgICBnZW9tX2RlbnNpdHkoYWRqdXN0ID0gYmluc19hZGp1c3QsIGZpbGwgPSBtZWRpb2NyZXRoZW1lczo6Y29sb3JzX3RhYmxlJGJhc2VbMl0sIGFscGhhID0gMC42KQogIH0gZWxzZSB7CiAgICBncmFwaCA8LSBncmFwaCArCiAgICAgIGdlb21faGlzdG9ncmFtKGJpbnMgPSBiaW5zX2FkanVzdCkKICB9CiAgCiAgICBncmFwaCA8LSBncmFwaCArCiAgICBzY2FsZV94X2NvbnRpbnVvdXModHJhbnMgPSAnbG9nMTAnKSArCiAgICBmYWNldF93cmFwKH5wb2xsdXRhbnQpICsKICAgIGxhYnModGl0bGUgPSAiUmVwYXJ0aXRpb24gb2YgdGhlIGxlbmd0aCBvZiBwZXJpb2RzIG9mIG1pc3NpbmcgZGF0YSIsIHN1YnRpdGxlID0gIkNvbXBhcmlzb24gYWNyb3NzIHBvbGx1dGFudHMgLSBPbmUgb2JzZXJ2YXRpb24gcGVyIHBlcmlvZCIsIHggPSAiTnVtYmVyIG9mIGNvbnNlY3V0aXZlIGhvdXJzIG9mIG1pc3NpbmcgZGF0YSIpIAogICAgCiAgICByZXR1cm4oZ3JhcGgpCn0KCmdyYXBoX2Rpc3RyaWJfbGVuZ3RoKGxlbmd0aF9taXNzaW5nX29uZV9wZXJfcGVyaW9kLCBkZW5zaXR5ID0gRkFMU0UsIGJpbnNfYWRqdXN0ID0gMjApCgpncmFwaF9kaXN0cmliX2xlbmd0aChsZW5ndGhfbWlzc2luZ19vbmVfcGVyX3BlcmlvZCwgZGVuc2l0eSA9IFRSVUUsIGJpbnNfYWRqdXN0ID0gNCkKCmxlbmd0aF9taXNzaW5nX29uZV9wZXJfcGVyaW9kICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBsZW5ndGhfcGVyaW9kX21pc3NpbmcpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDIwKSArCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gJ2xvZzEwJykgKwogIGZhY2V0X3dyYXAofnBvbGx1dGFudCkgKwogIAoKbGVuZ3RoX21pc3Npbmdfb25lX3Blcl9wZXJpb2QgJT4lIAogIGdncGxvdChhZXMoeCA9IGxlbmd0aF9wZXJpb2RfbWlzc2luZykpICsKICBnZW9tX2RlbnNpdHkoYWRqdXN0ID0gNCwgZmlsbCA9IG1lZGlvY3JldGhlbWVzOjpjb2xvcnNfdGFibGUkYmFzZVsyXSwgYWxwaGEgPSAwLjYpICsKICBzY2FsZV94X2NvbnRpbnVvdXModHJhbnMgPSAnbG9nMTAnKSArCiAgZmFjZXRfd3JhcCh+cG9sbHV0YW50KSArCiAgbGFicyh0aXRsZSA9ICJSZXBhcnRpdGlvbiBvZiB0aGUgbGVuZ3RoIG9mIHBlcmlvZHMgb2YgbWlzc2luZyBkYXRhIiwgc3VidGl0bGUgPSAiQ29tcGFyaXNvbiBhY3Jvc3MgcG9sbHV0YW50cyAtIE9uZSBvYnNlcnZhdGlvbiBwZXIgcGVyaW9kIiwgeCA9ICJOdW1iZXIgb2YgY29uc2VjdXRpdmUgaG91cnMgb2YgbWlzc2luZyBkYXRhIiwgeSA9ICJEZW5zaXR5IikgCmBgYAoKYGBge3J9Cmxlbmd0aF9taXNzaW5nX2RhdGEgJT4lIAogIGdncGxvdChhZXMoeCA9IGxlbmd0aF9wZXJpb2RfbWlzc2luZykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjApICsKICBzY2FsZV94X2NvbnRpbnVvdXModHJhbnMgPSAnbG9nMTAnKSArCiAgZmFjZXRfd3JhcCh+cG9sbHV0YW50KSArCiAgbGFicyh0aXRsZSA9ICJSZXBhcnRpdGlvbiBvZiB0aGUgbGVuZ3RoIG9mIHBlcmlvZHMgb2YgbWlzc2luZyBkYXRhIiwgc3VidGl0bGUgPSAiQ29tcGFyaXNvbiBhY3Jvc3MgcG9sbHV0YW50cyAtIE9uZSBvYnNlcnZhdGlvbiBwZXIgZGF0ZSIsIHggPSAiTnVtYmVyIG9mIGNvbnNlY3V0aXZlIGhvdXJzIG9mIG1pc3NpbmcgZGF0YSIsIHkgPSAgIkNvdW50IikgCgpsZW5ndGhfbWlzc2luZ19kYXRhICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBsZW5ndGhfcGVyaW9kX21pc3NpbmcpKSArCiAgZ2VvbV9kZW5zaXR5KGFkanVzdCA9IDIsIGZpbGwgPSBtZWRpb2NyZXRoZW1lczo6Y29sb3JzX3RhYmxlJGJhc2VbMl0sIGFscGhhID0gMC42KSArCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gJ2xvZzEwJykgKwogIGZhY2V0X3dyYXAofnBvbGx1dGFudCkgKwogIGxhYnModGl0bGUgPSAiUmVwYXJ0aXRpb24gb2YgdGhlIGxlbmd0aCBvZiBwZXJpb2RzIG9mIG1pc3NpbmcgZGF0YSIsIHN1YnRpdGxlID0gIkNvbXBhcmlzb24gYWNyb3NzIHBvbGx1dGFudHMgLSBPbmUgb2JzZXJ2YXRpb24gcGVyIGRhdGUiLCB4ID0gIk51bWJlciBvZiBjb25zZWN1dGl2ZSBob3VycyBvZiBtaXNzaW5nIGRhdGEiLCB5ID0gIkRlbnNpdHkiKSAKYGBgCgpgYGB7cn0KbGVuZ3RoX21pc3Npbmdfb25lX3Blcl9wZXJpb2QgJT4lIAogIG11dGF0ZShtaXNzaW5nX2xvbmdlcl9kYXkgPSBpZmVsc2UobGVuZ3RoX3BlcmlvZF9taXNzaW5nID4gMjQsIFRSVUUsIEZBTFNFKSkgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IG1pc3NpbmdfbG9uZ2VyX2RheSksIHN0YXQgPSAiY291bnQiKSArIAogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIHBlcmlvZHMgd2l0aCBtaXNzaW5nIGRhdGEgbG9uZ2VyL3Nob3J0ZXIgdGhhbiBhIGRheSIsIHN1YnRpdGxlID0gIk9uZSBvYnNlcnZhdGlvbiBwZXIgcGVyaW9kIiwgeCA9ICJNaXNzaW5nIHBlcmlvZCBsb25nZXIgdGhhbiBhIGRheSIsIHkgPSAgIkNvdW50IikgCmBgYAoKYGBge3J9Cmxlbmd0aF9taXNzaW5nX2RhdGEgJT4lIAogIG11dGF0ZShtaXNzaW5nX2xvbmdlcl9kYXkgPSBpZmVsc2UobGVuZ3RoX3BlcmlvZF9taXNzaW5nID4gMjQsIFRSVUUsIEZBTFNFKSkgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IG1pc3NpbmdfbG9uZ2VyX2RheSksIHN0YXQgPSAiY291bnQiKSArIAogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIHBlcmlvZHMgd2l0aCBtaXNzaW5nIGRhdGEgbG9uZ2VyL3Nob3J0ZXIgdGhhbiBhIGRheSIsIHN1YnRpdGxlID0gIk9uZSBvYnNlcnZhdGlvbiBwZXIgZGF0ZSIsIHggPSAiTWlzc2luZyBwZXJpb2QgbG9uZ2VyIHRoYW4gYSBkYXkiLCB5ID0gICJDb3VudCIpIApgYGAKCiMjIyBDb29yZWxhdGlvbiBiZXR3ZWVuIG1pc3NpbmduZXNzIGxlbmd0aCBhbmQgd2VhdGhlciB2YXJpYWJsZXMKCmBgYHtyfQpwbG90X2V2b2x1dGlvbl9sZW5ndGggPC0gZnVuY3Rpb24oZGYsIHZhciwgcGVyKSB7CiAgdmFyX25hbWUgPC0gc3RyX3JlcGxhY2VfYWxsKHZhciwgcGF0dGVybiA9ICJfIiwgcmVwbGFjZW1lbnQgPSAiICIpCiAgCiAgZ3JhcGggPC0gZGYgJT4lIAogICAgZ2dwbG90KCkgKyAKICAgIGdlb21fYmluMmQoYWVzKHggPSAuZGF0YVtbdmFyXV0sIHkgPSAuZGF0YVtbImxlbmd0aF9wZXJpb2RfbWlzc2luZyJdXSkpICsKICAgIHNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICdsb2cxMCcpICsgCiAgICBsYWJzKHRpdGxlID0gcGFzdGUoIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIGxlbmd0aCBvZiBwZXJpb2RzIHdpdGggbWlzc2luZyBkYXRhIiwgdmFyX25hbWUpLCBzdWJ0aXRsZSA9IHBhc3RlKCJPbmUgb2JzZXJ2YXRpb24gcGVyIiwgcGVyKSwgeCA9IHN0cl90b19zZW50ZW5jZSh2YXJfbmFtZSksIHkgPSAgIkxlbmd0aCBvZiBtaXNzaW5nIHBlcmlvZCAoaW4gaG91cnMpIikgCiAgCiAgaWYgKHN1YnN0cih2YXIsIDEsIDgpID09ICJ3aW5kX2RpciIpIHsKICAgIGdyYXBoIDwtIGdyYXBoICsKICAgICAgY29vcmRfcG9sYXIoKQogIH0KICAgIAogIHJldHVybihncmFwaCkKfQpgYGAKCgpgYGB7cn0KcHVycnI6Om1hcChjb3ZhcmlhdGVzX3dlYXRoZXIsIHBsb3RfZXZvbHV0aW9uX2xlbmd0aCwgZGYgPSBsZW5ndGhfbWlzc2luZ19kYXRhLCBwZXIgPSAiZGF0ZSIpCmBgYAoKSGVyZSB3ZSBjb25zaWRlciB0aGUgd2VhdGhlciB3aGVuIHZhcmlhYmxlcyBzdGFydGVkIG1pc3NpbmcuIEl0IG1ha2Ugc2Vuc2UgdG8gbG9vayBpbnRvIHRoaXMgYmVjYXVzZSBpZiBtaXNzaW5nbmVzcyBpcyBjYXVzZWQgYnkgc29tZSB3ZWF0aGVyIGZlYXR1cmUsIFRoZSB3ZWF0aGVyIGR1cmluZyB0aGUgZmlyc3QgbWlzc2luZyBvYnNlcnZhdGlvbiB3b3VsZCBiZSB0aGUgb25lIHRvIGxvb2sgaW50by4KCmBgYHtyfQp3ZWF0aGVyX2xlbmd0aF9kYXRhIDwtIGxlbmd0aF9taXNzaW5nX2RhdGEgJT4lIAogIGdyb3VwX2J5KG1pc3NpbmdfcGVyaW9kX2lkKSAlPiUgCiAgbXV0YXRlKG9ic2VydmF0aW9uX251bWJlciA9IHJvd19udW1iZXIoKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZmlsdGVyKG9ic2VydmF0aW9uX251bWJlciA9PSAxKSAKCnB1cnJyOjptYXAoY292YXJpYXRlc193ZWF0aGVyLCBwbG90X2V2b2x1dGlvbl9sZW5ndGgsIGRmID0gd2VhdGhlcl9sZW5ndGhfZGF0YSwgcGVyID0gInBlcmlvZCIpCmBgYAoKCgoKCg==